#include "./tools_interface.h"
#include "../layout/layout.hpp"
#include "../ui_message/message.h"
#include "auto_route/model.h"
#include "auto_route_interface.h"
#include "grpc_interface.h"
#include "layer_interface.h"
#include "select/select_cmd.hpp"
#include "setting_interface.h"

namespace qbe::tools {
void exit(ecs::Query query, state::AllModeType enter_mode) {
  auto& interface_objcet = query.get_resource<InterfaceObjcet>();
  if (interface_objcet.exit) {
    interface_objcet.exit(enter_mode);
  }
}
std::vector<entt::entity> filter_select(ecs::Query query, std::multimap<double, entt::entity> sel_e) {
  auto& current_cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& autoroute_model = query.get_resource<autoroute::SelPointLineRangeModel>();
  std::vector<entt::entity> result;
  for (auto i : sel_e) {
    if (autoroute_model.select_ele_ctrl == 0) {
      result.push_back(i.second);
    } else if (autoroute_model.select_ele_ctrl == 1) {
      auto _ptr = current_cell->reg.try_get<qlib::Path::s_ptr>(i.second);
      if (!_ptr)
        continue;
      auto line = *_ptr;
      if (line->type != qlib::PathType::Spine)
        continue;
      if (line->spine.points.size() > 2) {
        continue;
      }
      result.push_back(i.second);
    } else if (autoroute_model.select_ele_ctrl == 2) {
      auto _ptr = current_cell->reg.try_get<qlib::Path::s_ptr>(i.second);
      if (!_ptr)
        continue;
      auto line = *_ptr;
      if (line->type != qlib::PathType::Spine)
        continue;
      if (line->spine.points.size() <= 2) {
        continue;
      }
      result.push_back(i.second);
    } else if (autoroute_model.select_ele_ctrl == 6) {
      auto _ptr = current_cell->reg.try_get<qlib::Path::s_ptr>(i.second);
      if (!_ptr)
        continue;
      auto line = *_ptr;
      if (line->type != qlib::PathType::Spine)
        continue;
      result.push_back(i.second);
    }
  }
  return result;
}
qbe::select::SelectCmd::PartMap filter_part_select(ecs::Query query, qbe::select::SelectCmd::PartMap& sels,
                                                   autoroute::SelPointLineRangeModel& range) {
  auto& current_cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& autoroute_model = query.get_resource<autoroute::SelPointLineRangeModel>();
  qbe::select::SelectCmd::PartMap result;
  for (auto& sel : sels) {
    auto pick_state = current_cell->reg.get<PickTag>(sel.first);
    if (pick_state.is_pick == true) {
      if (autoroute_model.select_ele_ctrl == 0) {
        result.insert(sel);
      } else if (autoroute_model.select_ele_ctrl == 3 || autoroute_model.select_ele_ctrl == 5) {
        auto ptr_line = current_cell->reg.try_get<qlib::Path::s_ptr>(sel.first);
        if (ptr_line) {
          result.insert(sel);
        }
      }
    }
  }
  if (range.select_parts_range.empty()) {
    return result;
  }
  sels = result;
  result.clear();
  for (auto& sel : sels) {
    auto iter = range.select_parts_range.find(sel.first);
    {
      qbe::select::SelectPartData data;
      data.points = sel.second.points;
      for (auto i : sel.second.point_id_map) {
        if (autoroute_model.select_ele_ctrl == 5) {
          break;
        }
        {
          if (iter != range.select_parts_range.end()) {
            if (iter->second.point_id_map.count(i.first)) {
              data.point_id_map.insert(i);
            }
          }
        }
      }
      for (auto i : sel.second.edge_id_map) {
        {
          if (iter != range.select_parts_range.end()) {
            if (iter->second.edge_id_map.count(i.first)) {
              data.edge_id_map.insert(i);
            }
          }
        }
      }

      if (!data.edge_id_map.empty() || !data.point_id_map.empty()) {
        result.insert({sel.first, data});
      }
    }
  }
  return result;
}
std::vector<RenderSelect> partSelectToCtrl(ecs::Query query, std::unordered_map<entt::entity, qbe::select::SelectPartData>& select_parts) {
  std::vector<RenderSelect> result;
  auto& cell_cmd = query.get_resource<layout::CellCmd>();
  auto& cell_reg = cell_cmd.cell->reg;
  for (auto i : select_parts) {
    // if (!(i.second.point_id_map.empty())) {
    //   // auto _ptr_poly = cell_reg.try_get<qlib::Polygon::s_ptr>(result.sel_entitys);
    //   // auto _ptr_elli = cell_reg.try_get<qlib::Ellipse::s_ptr>(result.sel_entitys);
    //   // if (_ptr_poly || _ptr_elli) {
    //   //   result.select_indexs.insert(select.id);
    //   //   for (int i = 0; i < select.points.size() - 1; i++)
    //   //     result.key_points.push_back(select.points[i]);
    //   // }
    auto _ptr_line = cell_reg.try_get<qlib::Path::s_ptr>(i.first);
    if (_ptr_line) {
      auto ptr = *_ptr_line;
      for (auto j : i.second.point_id_map) {
        RenderSelect sel;
        sel.sel_entitys = i.first;
        sel.select_indexs.push_back(j.first);
        sel.key_points = ptr->spine.points;
        result.push_back(sel);
      }
    }
    // }

    if (!(i.second.edge_id_map.empty())) {
      // auto _ptr_poly = cell_reg.try_get<qlib::Polygon::s_ptr>(result.sel_entitys);
      // auto _ptr_elli = cell_reg.try_get<qlib::Ellipse::s_ptr>(result.sel_entitys);
      // auto _ptr_rec = cell_reg.try_get<qlib::Rectangle::s_ptr>(result.sel_entitys);
      // if (_ptr_poly || _ptr_elli || _ptr_rec) {
      //   result.select_indexs.insert(select.id);
      //   if ((select.id + 1) == (select.points.size() - 1)) {
      //     result.select_indexs.insert(0);
      //   } else {
      //     result.select_indexs.insert(select.id + 1);
      //   }

      //   // for (int i = 0; i < select.points.size() - 1; i++)
      //   // result.key_points.push_back(select.points[i]);
      // }

      auto _ptr_line = cell_reg.try_get<qlib::Path::s_ptr>(i.first);
      if (_ptr_line) {
        auto ptr = *_ptr_line;
        for (auto j : i.second.edge_id_map) {
          RenderSelect sel;
          sel.sel_entitys = i.first;
          sel.select_indexs.push_back(j.first);
          sel.select_indexs.push_back(j.first + 1);
          sel.key_points = ptr->spine.points;
          result.push_back(sel);
        }
      }
    }
  }

  return result;
}
void init(entt::registry& reg, ecs::Commands commands, ecs::Query query) {
  auto& state = query.get_resource<state::State>();
  state.cjExitCall(exit);

  for (auto [e, tran] : reg.view<qbe::render::SceneTag, vsg::ref_ptr<vsg::MatrixTransform>>().each()) {
    auto switchObject = vsg::Switch::create();
    tran->addChild(switchObject);
    commands.spawn(TempRenderTag{}, switchObject);
  }
}

void update(ecs::Query query, ecs::Bus& bus) {

  auto& hand = query.get_resource<vsg::ref_ptr<input::HandleBundle>>();
  auto& axis = query.get_resource<axis::Axis>();
  auto& current_cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& sel_and_pre_sel_set = query.get_resource<SelectedAndPreSelected>();
  auto& select_cmd = query.get_resource<select::SelectCmd>();
  auto& autoroute_model = query.get_resource<autoroute::SelPointLineRangeModel>();
  auto& state = query.get_resource<state::State>();

  static bool mouse_left_press = false;
  auto& select_events = query.get_event_reader<select::Event>();
  auto edit_mode = state.getEditingMode();

  if ((edit_mode == state::EditingModeType::AutoRouteFixedDistanceStretchLine || edit_mode == state::EditingModeType::AutoRoutePushLine ||
       edit_mode == state::EditingModeType::AutoRouteStretchLine || edit_mode == state::EditingModeType::ConfirmLineLength ||
       edit_mode == state::EditingModeType::FilletTool || edit_mode == state::EditingModeType::LineAddCorner) &&
      autoroute_model.is_open_selet == true) {
    select_cmd.query_nodes(axis.real_x, axis.real_y);
    {
      //整体选择
      bool is_touch = false;
      //部分选择
      if (hand->mouseReleased(1) && autoroute_model.is_part_select == true) {
        select_cmd.clear_parts();
        select_cmd.clear_select_parts();
        std::vector<RenderSelect>& selected = sel_and_pre_sel_set.selected;
        selected.clear();
        select::SelectCmd::PartMap select_parts;
        select_cmd.get_part(axis.real_x, axis.real_y, select_parts);
        auto res = filter_part_select(query, select_parts, autoroute_model);
        select_cmd.add_select_parts(res);
        select_parts = select_cmd.select_parts();
        auto temp = partSelectToCtrl(query, select_parts);
        selected.insert(selected.end(), temp.begin(), temp.end());
        if (!selected.empty())
          is_touch = true;
      }

      if (hand->mouseReleased(1) && autoroute_model.is_part_select == false) {
        select_cmd.clear_select();
        std::multimap<double, entt::entity> res_border;
        select_cmd.get_select(axis.real_x, axis.real_y, res_border);
        auto filter_e = filter_select(query, res_border);
        std::vector<RenderSelect>& selected = sel_and_pre_sel_set.selected;
        selected.clear();
        std::vector<entt::entity> e_arr;
        for (auto i : filter_e) {
          RenderSelect temp;
          temp.sel_entitys = i;
          selected.push_back(temp);
          e_arr.push_back(i);
          is_touch = true;
        }
        select_cmd.add_selects(e_arr);
      }

      if (is_touch == true) {
        std::vector<RenderSelect>& selected = sel_and_pre_sel_set.selected;
        auto& interface_objcet = query.get_resource<InterfaceObjcet>();
        if (interface_objcet.select_event)
          interface_objcet.select_event(axis.real_x, axis.real_y, selected);
      }
    }

    {
      //整体预选择
      std::vector<RenderSelect>& pre_select = sel_and_pre_sel_set.pre_selected;
      pre_select.clear();
      bool is_touch = false;
      //部分预选择
      if ((hand->mouse_move || hand->mousePressed(vsg::ButtonMask::BUTTON_MASK_1)) && autoroute_model.is_part_select == true) {
        select_cmd.clear_hover_parts();
        select::SelectCmd::PartMap select_parts;
        select_cmd.get_part(axis.real_x, axis.real_y, select_parts);
        auto res = filter_part_select(query, select_parts, autoroute_model);
        select_cmd.add_hover_parts(res);
        select_parts = select_cmd.hover_parts();
        auto temp = partSelectToCtrl(query, select_parts);
        pre_select.insert(pre_select.end(), temp.begin(), temp.end());
        if (!pre_select.empty())
          is_touch = true;
      }

      if ((hand->mouse_move || hand->mousePressed(vsg::ButtonMask::BUTTON_MASK_1)) && autoroute_model.is_part_select == false) {
        select_cmd.clear_hover();
        std::multimap<double, entt::entity> res_border;
        select_cmd.get_select(axis.real_x, axis.real_y, res_border);
        auto filter_e = filter_select(query, res_border);
        std::vector<entt::entity> e_arr;
        for (auto i : filter_e) {
          RenderSelect temp;
          temp.sel_entitys = i;
          pre_select.push_back(temp);
          e_arr.push_back(i);
          is_touch = true;
        }
        select_cmd.add_hovers(e_arr);
      }

      if (is_touch == true) {
        auto& interface_objcet = query.get_resource<InterfaceObjcet>();
        if (interface_objcet.pre_select_event)
          interface_objcet.pre_select_event(axis.real_x, axis.real_y, pre_select);
      }
    }
  }

  auto res = bus.receive<UiMessage::AddOperatorMessage>();
  if (!res.empty()) {
    for (auto& i : res)
      addOperator(query, bus, i.add_graphs, i.delete_graphs, i.new_cells);
  }

  //点击鼠标左键
  if (hand->mousePressed(vsg::ButtonMask::BUTTON_MASK_1)) {
    auto& interface_objcet = query.get_resource<InterfaceObjcet>();
    if (interface_objcet.mouse_left_press) {
      interface_objcet.mouse_left_press(axis.real_x, axis.real_y);
    }
    mouse_left_press = true;
  }
  //点击鼠标右键
  if (hand->mousePressed(vsg::ButtonMask::BUTTON_MASK_3)) {
    auto& interface_objcet = query.get_resource<InterfaceObjcet>();
    if (interface_objcet.mouse_right_press) {
      interface_objcet.mouse_right_press(axis.real_x, axis.real_y);
    }
  }

  //释放鼠标左键
  if (hand->mouseReleased(1)) {
    auto& interface_objcet = query.get_resource<InterfaceObjcet>();
    if (interface_objcet.mouse_left_release) {
      interface_objcet.mouse_left_release(axis.real_x, axis.real_y);
    }
    mouse_left_press = false;
  }

  //释放鼠标右键
  if (hand->mouseReleased(3)) {
    auto& interface_objcet = query.get_resource<InterfaceObjcet>();
    if (interface_objcet.mouse_right_release) {
      interface_objcet.mouse_right_release(axis.real_x, axis.real_y);
    }
    mouse_left_press = false;
  }

  if (hand->mouse_move) {
    auto& interface_objcet = query.get_resource<InterfaceObjcet>();
    if (mouse_left_press == true) {
      //鼠标左键拖动
      if (interface_objcet.mouse_left_drag) {
        interface_objcet.mouse_left_drag(axis.real_x, axis.real_y);
      }
    }

    //移动
    if (interface_objcet.mouse_move) {
      interface_objcet.mouse_move(axis.real_x, axis.real_y);
    }
  }
}
void addOperator(ecs::Query query, ecs::Bus& bus, std::vector<std::any> add_graphs, std::vector<entt::entity> delete_graphs,
                 std::vector<qlib::Cell::s_ptr> new_cells) {
  // SPDLOG_INFO("[tools_interface] addOperator_begin");
  auto& layout_cmd = query.get_resource<layout::LayoutCmd>();
  auto& unredoMoudel = query.get_resource<undoRedoT::UndoRedoModule>();
  auto& current_cell = query.get_resource<qlib::Cell::s_ptr>();
  auto& current_lib = query.get_resource<qlib::Library::s_ptr>();

  unredoMoudel.start(current_cell);

  std::vector<qlib::Polygon::s_ptr> polygons;
  std::vector<qlib::Rectangle::s_ptr> rectangles;
  std::vector<qlib::Ellipse::s_ptr> ellipses;
  std::vector<qlib::Fan::s_ptr> fans;
  std::vector<qlib::Path::s_ptr> lines;
  std::vector<qlib::Text::s_ptr> texts;
  std::vector<qlib::Label::s_ptr> labels;
  std::vector<qlib::Reference::s_ptr> references;

  for (auto g : add_graphs) {
    const std::type_info& stored_type = g.type();
    if (stored_type == typeid(qlib::Polygon::s_ptr)) {
      qlib::Polygon::s_ptr poly = std::any_cast<qlib::Polygon::s_ptr>(g);
      polygons.push_back(poly);
    } else if (stored_type == typeid(qlib::Rectangle::s_ptr)) {
      qlib::Rectangle::s_ptr rec = std::any_cast<qlib::Rectangle::s_ptr>(g);
      rectangles.push_back(rec);
    } else if (stored_type == typeid(qlib::Ellipse::s_ptr)) {
      qlib::Ellipse::s_ptr elli = std::any_cast<qlib::Ellipse::s_ptr>(g);
      ellipses.push_back(elli);
    } else if (stored_type == typeid(qlib::Fan::s_ptr)) {
      qlib::Fan::s_ptr fan = std::any_cast<qlib::Fan::s_ptr>(g);
      fans.push_back(fan);
    } else if (stored_type == typeid(qlib::Path::s_ptr)) {
      qlib::Path::s_ptr line = std::any_cast<qlib::Path::s_ptr>(g);
      lines.push_back(line);
    } else if (stored_type == typeid(qlib::Label::s_ptr)) {
      qlib::Label::s_ptr lable = std::any_cast<qlib::Label::s_ptr>(g);
      labels.push_back(lable);
    } else if (stored_type == typeid(qlib::Text::s_ptr)) {
      qlib::Text::s_ptr text = std::any_cast<qlib::Text::s_ptr>(g);
      texts.push_back(text);
    } else if (stored_type == typeid(qlib::Reference::s_ptr)) {
      qlib::Reference::s_ptr ref = std::any_cast<qlib::Reference::s_ptr>(g);
      references.push_back(ref);
    }
  }
  if (!polygons.empty())
    unredoMoudel.add(layout_cmd.add<qlib::Polygon::s_ptr>(polygons));
  if (!rectangles.empty())
    unredoMoudel.add(layout_cmd.add<qlib::Rectangle::s_ptr>(rectangles));
  if (!ellipses.empty())
    unredoMoudel.add(layout_cmd.add<qlib::Ellipse::s_ptr>(ellipses));
  if (!fans.empty())
    unredoMoudel.add(layout_cmd.add<qlib::Fan::s_ptr>(fans));
  if (!texts.empty())
    unredoMoudel.add(layout_cmd.add<qlib::Text::s_ptr>(texts));
  if (!lines.empty())
    unredoMoudel.add(layout_cmd.add<qlib::Path::s_ptr>(lines));
  if (!labels.empty())
    unredoMoudel.add(layout_cmd.add<qlib::Label::s_ptr>(labels));
  if (!references.empty()) {
    for (auto cell : new_cells) {
      layout_cmd.add_cell(cell);
    }
    unredoMoudel.add(layout_cmd.add<qlib::Reference::s_ptr>(references));
  }
  // SPDLOG_INFO("[tools_interface] dele_begin");
  unredoMoudel.dele(delete_graphs);
  // SPDLOG_INFO("[tools_interface] dele_end");
  layout_cmd.remove(delete_graphs);
  // SPDLOG_INFO("[tools_interface] remove_end");
  unredoMoudel.end();
  // SPDLOG_INFO("[tools_interface] unredoMoudel_end");
  layout_cmd.render_update();
  // SPDLOG_INFO("[tools_interface] render_update_end");
  bus.send<qbe::UiMessage::UpdateFileLisetFromLibrary>(qbe::UiMessage::UpdateFileLisetFromLibrary{current_lib});
  // SPDLOG_INFO("[tools_interface] addOperator_end");
}
void ToolsInterfacePlugin::build(ecs::App& app) {
  app.init_resource<SettingInterfaceObjcet>(SettingInterfaceObjcet{});
  app.init_resource<InterfaceObjcet>(InterfaceObjcet{});
  app.init_resource<LayerInterfaceObjcet>(LayerInterfaceObjcet{});
  app.init_resource<GrpcInterfaceObjcet>(GrpcInterfaceObjcet{});
  app.init_resource<SelectedAndPreSelected>(SelectedAndPreSelected{});
  app.init_resource<AutoRouteInterfaceObjcet>(AutoRouteInterfaceObjcet{});
  app.init_resource<autoroute::SelPointLineRangeModel>(autoroute::SelPointLineRangeModel{});
  app.add_systems<ecs::stage::Startup>(init);
  app.add_systems<ecs::stage::Update>(update);
}

}  // namespace qbe::tools